package com.xbongbong.paas.service.recheck;

import com.alibaba.fastjson.JSONArray;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.RecheckingAddRuleHelp;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.dto.FormDataRepeatDTO;
import com.xbongbong.paas.pojo.vo.CheckRepeatVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.recheck.pojo.RecheckAttrRulePojo;
import com.xbongbong.pro.recheck.pojo.RecheckFormRulePojo;
import com.xbongbong.pro.recheck.pojo.dto.RecheckAddEditDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.RecheckingRuleEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.model.IndexTypeModel;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @description 线索新建编辑页判重策略实现
 * @author yanglei
 * @date 2022/11/16 18:55
 */
@Service("clueRecheckAddEditStrategyImpl")
public class ClueRecheckAddEditStrategyImpl extends AbstractRecheckAddEditStrategy {

    private static final Logger LOG = LoggerFactory.getLogger(ClueRecheckAddEditStrategyImpl.class);

    @Resource
    private RecheckingAddRuleHelp recheckingAddRuleHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private PaasFormModel paasFormModel;

    @Override
    public Integer businessType() {
        return XbbRefTypeEnum.CLUE.getCode();
    }

    @Override
    public CheckRepeatVO abstractExecuteRule(FormDataRepeatDTO formDataRepeatDTO) throws XbbException{
        CheckRepeatVO checkRepeatVO = new CheckRepeatVO();
        BoolQueryBuilder checkToolBoolQuery = boolQuery();
        BoolQueryBuilder noRepeatBoolQuery = boolQuery();
        RecheckAddEditDTO recheckAddEditDTO = new RecheckAddEditDTO();
        //设置顶级传参
        setCommonRecheckAddEditDTO(formDataRepeatDTO,recheckAddEditDTO,checkRepeatVO);
        setSpecialRecheckAddEditDTO(formDataRepeatDTO,recheckAddEditDTO,checkRepeatVO);
        //设置公共条件
        setCommonCondition(recheckAddEditDTO,checkToolBoolQuery,noRepeatBoolQuery);
        //处理系统字段查重查询条件
        handleSystemAttrQueryBuilder(recheckAddEditDTO,checkToolBoolQuery,noRepeatBoolQuery);
        //处理自定义字段查询条件
        handleCustomAttrQueryBuilder(recheckAddEditDTO,checkToolBoolQuery,noRepeatBoolQuery);
        //如果新建不允许重复查出来的数据为空,再去用查重工具规则查
        List<PaasFormDataEntityExt> noRepeatDataList = queryResult(recheckAddEditDTO, noRepeatBoolQuery);
        //导入不需要校验查重工具规则
        if (!recheckAddEditDTO.getIsImport() && recheckAddEditDTO.getIsRecheckPermission() && recheckAddEditDTO.getIsEdit()){
            List<PaasFormDataEntityExt> checkToolDataList = queryResult(recheckAddEditDTO, checkToolBoolQuery);
            recheckAddEditDTO.getCheckToolDataMap().put(businessType(),checkToolDataList);
        }
        recheckAddEditDTO.getNoRepeatDataMap().put(businessType(),noRepeatDataList);
        //名称字段在审批中的处理
        handleNameInApproval(recheckAddEditDTO);
        //线索独有,线索联合查客户和联系人
        handleCustomerAndContact(recheckAddEditDTO);
        return resultDeal(recheckAddEditDTO);
    }

    @Override
    public CheckRepeatVO resultDeal(RecheckAddEditDTO recheckAddEditDTO) throws XbbException {
        CheckRepeatVO checkRepeatVO = recheckAddEditDTO.getCheckRepeatVO();
        Map<Integer, List<PaasFormDataEntityExt>> noRepeatDataMap = recheckAddEditDTO.getNoRepeatDataMap();
        Map<Integer, List<PaasFormDataEntityExt>> checkToolDataMap = recheckAddEditDTO.getCheckToolDataMap();
        //当前业务本身出来的重复数据
        List<PaasFormDataEntityExt> noRepeatCurrentDataList = noRepeatDataMap.getOrDefault(businessType(), new ArrayList<>());
        List<PaasFormDataEntityExt> checkToolCurrentDataList = checkToolDataMap.getOrDefault(businessType(), new ArrayList<>());
        //线索联合客户查出来的重复数据
        List<PaasFormDataEntityExt> noRepeatCustomerDataList = noRepeatDataMap.getOrDefault(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), new ArrayList<>());
        List<PaasFormDataEntityExt> checkToolCustomerDataList = checkToolDataMap.getOrDefault(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), new ArrayList<>());
        //线索联合联系人查出来的重复数据
        List<PaasFormDataEntityExt> noRepeatContactDataList = noRepeatDataMap.getOrDefault(XbbRefTypeEnum.CONTACT.getCode(), new ArrayList<>());
        List<PaasFormDataEntityExt> CheckToolContactDataList = checkToolDataMap.getOrDefault(XbbRefTypeEnum.CONTACT.getCode(), new ArrayList<>());
        //是编辑触发接口，将dataId相同的数据移除
        Long dataId = recheckAddEditDTO.getDataId();
        if (Objects.nonNull(dataId)){
            if (CollectionsUtil.isNotEmpty(noRepeatCurrentDataList)){
                noRepeatCurrentDataList.removeIf(item -> Objects.nonNull(item.getId()) && Objects.equals(dataId, item.getId()));
            }
            if (CollectionsUtil.isNotEmpty(checkToolCurrentDataList)) {
                checkToolCurrentDataList.removeIf(item -> Objects.nonNull(item.getId()) && Objects.equals(dataId, item.getId()));
            }
        }
        List<PaasFormDataEntityExt> totalNoRepeatDataList = new ArrayList<>();
        List<PaasFormDataEntityExt> totalCheckToolDataList = new ArrayList<>();
        totalNoRepeatDataList.addAll(noRepeatCurrentDataList);
        totalNoRepeatDataList.addAll(noRepeatCustomerDataList);
        totalNoRepeatDataList.addAll(noRepeatContactDataList);
        totalCheckToolDataList.addAll(checkToolCurrentDataList);
        totalCheckToolDataList.addAll(checkToolCustomerDataList);
        totalCheckToolDataList.addAll(CheckToolContactDataList);
        setCheckType(checkRepeatVO,totalNoRepeatDataList,totalCheckToolDataList);
        setManyRepeat(recheckAddEditDTO,checkRepeatVO,totalNoRepeatDataList,totalNoRepeatDataList);
        return checkRepeatVO;
    }
    @Override
    public void setSpecialRecheckAddEditDTO(FormDataRepeatDTO formDataRepeatDTO, RecheckAddEditDTO recheckAddEditDTO, CheckRepeatVO checkRepeatVO) throws XbbException {
        //查重权限
        Boolean recheckPermission = !Objects.equals("-3", formDataRepeatDTO.getUserId()) && formDataRepeatDTO.getLoginUser().getPermSet().contains(ProPermissionAliasEnum.CLUE_DUPLICATE.getAlias());
        recheckAddEditDTO.setIsRecheckPermission(recheckPermission);
        recheckAddEditDTO.setSubIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        recheckAddEditDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CLUE);
        recheckAddEditDTO.setNameAttr(ClueEnum.COMPANY_NAME.getAttr());
    }

    @Override
    public void handleSystemAttrQueryBuilder(RecheckAddEditDTO recheckAddEditDTO ,BoolQueryBuilder checkToolBoolQuery,BoolQueryBuilder noRepeatBoolQuery) throws XbbException{
        CheckRepeatVO checkRepeatVO = recheckAddEditDTO.getCheckRepeatVO();
        RecheckingRuleEntity ruleEntity = recheckAddEditDTO.getRuleEntity();
        Boolean isEdit = recheckAddEditDTO.getIsEdit();
        try{
            //新建不允许重复规则
            List<RecheckFormRulePojo> noRepeatRule = JSONArray.parseArray(ruleEntity.getNoRepeatRule(), RecheckFormRulePojo.class);
            //查重工具规则
            List<RecheckFormRulePojo> checkToolRule = JSONArray.parseArray(ruleEntity.getCheckToolRule(), RecheckFormRulePojo.class);
            if(isEdit){
                checkRepeatVO.setCheckType(BasicConstant.TWO);
                //代表新建编辑页的鼠标失去焦点动作，需要封装查重工具规则和新建不允许重复规则，拥有查重工具权限才要封装查重工具规则
                if (recheckAddEditDTO.getIsRecheckPermission()){
                    checkRepeatVO.setCheckType(BasicConstant.TWO);
                    handleSystemRecheckingRule(checkToolRule,recheckAddEditDTO,checkToolBoolQuery);
                }
            }
            //否则代表新建编辑保存时的动作，只需要封装新建不允许重复规则
            handleSystemRecheckingRule(noRepeatRule,recheckAddEditDTO,noRepeatBoolQuery);
        }catch (Exception e){
            LOG.error("系统字段查询数据重复出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    /**
     * @description 线索联合查重 查客户、查线索
     * @author yanglei
     * @date 2022/11/17 9:34
     * @param recheckAddEditDTO 上下文传参
     */
    public void handleCustomerAndContact(RecheckAddEditDTO recheckAddEditDTO) throws XbbException{
        RecheckingRuleEntity ruleEntity = recheckAddEditDTO.getRuleEntity();
        try{
            Integer feeType = recheckAddEditDTO.getFeeType();
            //先判断公司版本，只有旗舰版、高级版有联合判重
            if (!(Objects.equals(PackageTypeEnum.ULTIMATE.getType(),feeType) || Objects.equals(PackageTypeEnum.ADVANCED.getType(),feeType))){
                return;
            }
            String corpid = recheckAddEditDTO.getCorpid();
            Integer customerBusinessType = XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode();
            //新建不允许重复规则
            List<RecheckFormRulePojo> noRepeatRule = JSONArray.parseArray(ruleEntity.getNoRepeatRule(), RecheckFormRulePojo.class);
            //查重工具规则
            List<RecheckFormRulePojo> checkToolRule = JSONArray.parseArray(ruleEntity.getCheckToolRule(), RecheckFormRulePojo.class);
            List<RecheckAttrRulePojo> linkCustomerNoRepeatRule = recheckingAddRuleHelp.getClueLinkRecheckAttrRulePojo(noRepeatRule, customerBusinessType);
            List<RecheckAttrRulePojo> linkCustomerCheckToolRule = recheckingAddRuleHelp.getClueLinkRecheckAttrRulePojo(checkToolRule, customerBusinessType);
            List<RecheckAttrRulePojo> linkContactNoRepeatRule = recheckingAddRuleHelp.getClueLinkRecheckAttrRulePojo(noRepeatRule, XbbRefTypeEnum.CONTACT.getCode());
            List<RecheckAttrRulePojo> linkContactCheckToolRule = recheckingAddRuleHelp.getClueLinkRecheckAttrRulePojo(checkToolRule, XbbRefTypeEnum.CONTACT.getCode());
            //是否是鼠标失去焦点逻辑
            boolean isCheckRule = recheckAddEditDTO.getIsEdit() && recheckAddEditDTO.getIsRecheckPermission();
            if (Objects.equals(PackageTypeEnum.ADVANCED.getType(),feeType)){
                List<String> list = Arrays.asList(StringConstant.NAME, StringConstant.PHONE);
                //高级版线索联合查重仅支持名称和电话字段，所以过滤一波
                linkCustomerNoRepeatRule.removeIf(item -> Objects.nonNull(item) && !list.contains(item.getAttr()));
                linkCustomerCheckToolRule.removeIf(item -> Objects.nonNull(item) && !list.contains(item.getAttr()));
                linkContactNoRepeatRule.removeIf(item -> Objects.nonNull(item) && !list.contains(item.getAttr()));
                linkContactCheckToolRule.removeIf(item -> Objects.nonNull(item) && !list.contains(item.getAttr()));
            }
            Map<Integer, List<PaasFormDataEntityExt>> noRepeatDataMap = recheckAddEditDTO.getNoRepeatDataMap();
            Map<Integer, List<PaasFormDataEntityExt>> checkToolDataMap = recheckAddEditDTO.getCheckToolDataMap();
            if (CollectionsUtil.isNotEmpty(linkCustomerNoRepeatRule)){
                recheckAddEditDTO.setBusinessType(customerBusinessType);
                recheckAddEditDTO.setIndexTypeEnum(indexTypeModel.getCustomerIndex(corpid,customerBusinessType, SaasMarkEnum.SAAS.getCode()));
                recheckAddEditDTO.setSubIndexTypeEnum(indexTypeModel.getCustomerSubIndex(corpid, customerBusinessType, SaasMarkEnum.SAAS.getCode()));
                getLinkTotalDataMap(recheckAddEditDTO,noRepeatDataMap,linkCustomerNoRepeatRule);
            }
            if (CollectionsUtil.isNotEmpty(linkCustomerCheckToolRule) && isCheckRule){
                recheckAddEditDTO.setBusinessType(customerBusinessType);
                recheckAddEditDTO.setIndexTypeEnum(indexTypeModel.getCustomerIndex(corpid,customerBusinessType, SaasMarkEnum.SAAS.getCode()));
                recheckAddEditDTO.setSubIndexTypeEnum(indexTypeModel.getCustomerSubIndex(corpid, customerBusinessType, SaasMarkEnum.SAAS.getCode()));
                getLinkTotalDataMap(recheckAddEditDTO,checkToolDataMap,linkCustomerCheckToolRule);
            }
            if(CollectionsUtil.isNotEmpty(linkContactNoRepeatRule)){
                recheckAddEditDTO.setBusinessType(XbbRefTypeEnum.CONTACT.getCode());
                recheckAddEditDTO.setSubIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CONTACT_SUB);
                recheckAddEditDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CONTACT);
                getLinkTotalDataMap(recheckAddEditDTO,noRepeatDataMap,linkContactNoRepeatRule);
            }
            if(CollectionsUtil.isNotEmpty(linkContactCheckToolRule) && isCheckRule){
                recheckAddEditDTO.setBusinessType(XbbRefTypeEnum.CONTACT.getCode());
                recheckAddEditDTO.setSubIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CONTACT_SUB);
                recheckAddEditDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CONTACT);
                getLinkTotalDataMap(recheckAddEditDTO,checkToolDataMap,linkContactCheckToolRule);
            }
            recheckAddEditDTO.setNoRepeatDataMap(noRepeatDataMap);
            recheckAddEditDTO.setCheckToolDataMap(checkToolDataMap);
        }catch (Exception e){
            LOG.error("系统字段查询数据重复出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private void getLinkTotalDataMap(RecheckAddEditDTO recheckAddEditDTO,Map<Integer, List<PaasFormDataEntityExt>> dataMap,List<RecheckAttrRulePojo> linkRuleList) throws XbbException {
        String attr = recheckAddEditDTO.getAttr();
        String subAttr = recheckAddEditDTO.getSubAttr();
        Integer businessType = recheckAddEditDTO.getBusinessType();
        if (StringUtil.isNotEmpty(subAttr)){
            //当前查重的是子表单类型
            attr = attr + "." + subAttr;
        }
        Long contactFormId = null;
        //获取一下联系人模板id,防止linkForm为空或者为0
        if (Objects.equals(businessType,XbbRefTypeEnum.CONTACT.getCode())){
            contactFormId = paasFormModel.getFormIdByBusinessType(recheckAddEditDTO.getCorpid(),businessType);
        }
        BoolQueryBuilder linkQueryBuilder = boolQuery();
        for (RecheckAttrRulePojo linkRule : linkRuleList){
            if(Objects.nonNull(linkRule) && Objects.equals(attr,linkRule.getAttr())){
                //证明该字段配置了线索查客户,获取线索联合客户查询的条件
                Long linkFormId = linkRule.getLinkFormId();
                if(Objects.equals(businessType,XbbRefTypeEnum.CONTACT.getCode())){
                    linkFormId = contactFormId;
                }
                getLinkQueryBuilder(linkQueryBuilder,recheckAddEditDTO, linkRule.getIsAll(), linkRule.getMatchWay(),linkRule.getLinkAttr(),linkFormId, recheckAddEditDTO.getSubIndexTypeEnum().getType());
                List<PaasFormDataEntityExt> linDataList = queryResult(recheckAddEditDTO, linkQueryBuilder);
                if(CollectionsUtil.isNotEmpty(linDataList)){
                    //线索联合客户查出来的客户重复数据
                    dataMap.put(businessType,linDataList);
                }
                //break;
            }
        }
    }

    /**
     * @description 获取线索查客户和联系人的查重条件封装
     * @author yanglei
     * @date 2022/11/17 14:31
     * @param boolQueryBuilder
     * @param recheckAddEditDTO
     * @param isAll 是否全部模板查重
     * @param attr 查询的客户或者线索attr
     * @param linkFormId 查询的客户或者线索 formId
     * @param subIndexType 客户或者联系人子表单索引type
     */
    public void getLinkQueryBuilder(BoolQueryBuilder boolQueryBuilder,RecheckAddEditDTO recheckAddEditDTO, Integer isAll, Integer macthWay,String attr, Long linkFormId, String subIndexType) throws XbbException{
        String corpid = recheckAddEditDTO.getCorpid();
        String value = recheckAddEditDTO.getValue().toString();
        Integer businessType = recheckAddEditDTO.getBusinessType();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        //回收站和审批通过的
        boolQueryBuilder.filter(termsQuery(ParameterConstant.DEL, Arrays.asList(DelEnum.NORMAL.getDel(),DelEnum.DELETE.getDel(),DelEnum.APPROVE_STATUS.getDel())));
        if (commonHelp.isOpenWorkFlow(corpid)) {
            // 如果开启了工作流，审批中数据会进入主表，查重的时候可以直接从主表查到
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
        } else {
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        }
        if (Objects.equals(BasicConstant.ONE, isAll)){
            //全部模版
            //获得客户的全部模版,关联的是客户的全部模版，子表单类型只能是电话字段
            List<Long> formIdIdList = new ArrayList<>();
            List<Long> allFormIdList = recheckingAddRuleHelp.getAllFormIdList(corpid, recheckAddEditDTO.getBusinessType());
            for (Long allCustomerFormId : allFormIdList){
                //判断关联的当前字段是否处于启用状态
                Map<String, FieldAttrEntity> explainMap = recheckingAddRuleHelp.getExplainMap(allCustomerFormId, corpid);
                if (Objects.isNull(explainMap)){
                    continue;
                }
                //根据linkAttr判断关联的是否是子表单类型
                String[] split = attr.split("\\.");
                FieldAttrEntity linkData;
                if (split.length > 1){
                    //说明关联的是子表单类型。全部模版只可能关联电话类型的子表单
                    List<String> subAttrList = new ArrayList<>(Arrays.asList(split));
                    //根据表单id查询解释，判断关联字段是否处于开启状态
                    linkData = explainMap.get(subAttrList.get(0));
                    if (Objects.nonNull(linkData)){
                        //不为空，说明当前模版的这个字段处于启用状态
                        SubFormPoJo subForm = linkData.getSubForm();
                        //判断内层的表单是否处于启用状态
                        if (Objects.nonNull(subForm) && CollectionsUtil.isNotEmpty(subForm.getItems())){
                            List<? extends FieldAttrEntity> items = subForm.getItems();
                            items.forEach(item -> {
                                if (Objects.equals(item.getAttr(), subAttrList.get(1))){
                                    formIdIdList.add(allCustomerFormId);
                                }
                            });
                        }
                    }
                }else {
                    //非子表单类型,不为空则说明没有处于回收站或未启用
                    if (Objects.nonNull(explainMap.get(attr))){
                        formIdIdList.add(allCustomerFormId);
                    }
                }
            }
            packageMatchBoolQueryBuilder(attr,Arrays.asList(value),boolQueryBuilder,formIdIdList,macthWay);
        }else if(Objects.equals(BasicConstant.ZERO, isAll) || Objects.equals(businessType,XbbRefTypeEnum.CONTACT.getCode())){
            //联系人和客户单模板走这里
            getLinkSubForm(macthWay,attr, linkFormId, boolQueryBuilder, recheckingAddRuleHelp.getExplainMap(linkFormId, corpid), subIndexType, recheckAddEditDTO);
        }
    }
}
